// Copyright (c) 2007 Robin Boerdijk. All rights reserved.
//
// This software is licensed under the terms of the Microsoft Reciprocal License as described 
// in the file LICENSE.txt, which you should have received as part of this distribution. The 
// license terms are also available at http://www.opensource.org/licenses/ms-rl.html.

#include "wtk/win32.h"
#include "wtkpc.h"

#include "wtk/Error.h"

#define WTK_WIN32_THROW(F) { throw Error(#F " failed"); }

#define WTK_WIN32_V0(F) \
	void F() { if (!::F()) WTK_WIN32_THROW(F) }

#define WTK_WIN32_V1(F, T1) \
	void F(T1 a) { if (!::F(a)) WTK_WIN32_THROW(F) }

#define WTK_WIN32_V2(F, T1, T2) \
	void F(T1 a, T2 b) { if (!::F(a, b)) WTK_WIN32_THROW(F) }

#define WTK_WIN32_V3(F, T1, T2, T3) \
	void F(T1 a, T2 b, T3 c) { if (!::F(a, b, c)) WTK_WIN32_THROW(F) }

#define WTK_WIN32_V4(F, T1, T2, T3, T4) \
	void F(T1 a, T2 b, T3 c, T4 d) { if (!::F(a, b, c, d)) WTK_WIN32_THROW(F) }

#define WTK_WIN32_V7(F, T1, T2, T3, T4, T5, T6, T7) \
	void F(T1 a, T2 b, T3 c, T4 d, T5 e, T6 f, T7 g) { if (!::F(a, b, c, d, e, f, g)) WTK_WIN32_THROW(F) }

#define WTK_WIN32_R0(RT, E, F) \
	RT F() { RT r = ::F(); if (r == E) WTK_WIN32_THROW(F) else return r; }

#define WTK_WIN32_R1(RT, E, F, T1) \
	RT F(T1 a) { RT r = ::F(a); if (r == E) WTK_WIN32_THROW(F) else return r; }

#define WTK_WIN32_R2(RT, E, F, T1, T2) \
	RT F(T1 a, T2 b) { RT r = ::F(a, b); if (r == E) WTK_WIN32_THROW(F) else return r; }

#define WTK_WIN32_R3(RT, E, F, T1, T2, T3) \
	RT F(T1 a, T2 b, T3 c) { RT r = ::F(a, b, c); if (r == E) WTK_WIN32_THROW(F) else return r; }

#define WTK_WIN32_R4(RT, E, F, T1, T2, T3, T4) \
	RT F(T1 a, T2 b, T3 c, T4 d) { RT r = ::F(a, b, c, d); if (r == E) WTK_WIN32_THROW(F) else return r; }

#define WTK_WIN32_R6(RT, E, F, T1, T2, T3, T4, T5, T6) \
	RT F(T1 a, T2 b, T3 c, T4 d, T5 e, T6 f) { RT r = ::F(a, b, c, d, e, f); if (r == E) WTK_WIN32_THROW(F) else return r; }

#define WTK_WIN32_R8(RT, E, F, T1, T2, T3, T4, T5, T6, T7, T8) \
	RT F(T1 a, T2 b, T3 c, T4 d, T5 e, T6 f, T7 g, T8 h) { RT r = ::F(a, b, c, d, e, f, g, h); if (r == E) WTK_WIN32_THROW(F) else return r; }

#define WTK_WIN32_R12(RT, E, F, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12) \
	RT F(T1 a, T2 b, T3 c, T4 d, T5 e, T6 f, T7 g, T8 h, T9 i, T10 j, T11 k, T12 l) { RT r = ::F(a, b, c, d, e, f, g, h, i, j, k, l); if (r == E) WTK_WIN32_THROW(F) else return r; }

#define WTK_WIN32_E1(RT, F, T1) \
	RT F(T1 a) { ::SetLastError(0); RT r = ::F(a); if (::GetLastError() != 0) WTK_WIN32_THROW(F) else return r; }

#define WTK_WIN32_E2(RT, F, T1, T2) \
	RT F(T1 a, T2 b) { ::SetLastError(0); RT r = ::F(a, b); if (::GetLastError() != 0) WTK_WIN32_THROW(F) else return r; }

#define WTK_WIN32_E3(RT, F, T1, T2, T3) \
	RT F(T1 a, T2 b, T3 c) { ::SetLastError(0); RT r = ::F(a, b, c); if (::GetLastError() != 0) WTK_WIN32_THROW(F) else return r; }

namespace wtk
{
	namespace win32
	{
		WTK_WIN32_V4(AdjustWindowRectEx, LPRECT, DWORD, BOOL, DWORD); 
		WTK_WIN32_R1(HDWP, NULL, BeginDeferWindowPos, int);
		WTK_WIN32_V1(CloseWindow, HWND);
		WTK_WIN32_R0(HMENU, NULL, CreateMenu);
		WTK_WIN32_R0(HMENU, NULL, CreatePopupMenu);
		WTK_WIN32_R12(HWND, NULL, CreateWindowExA, DWORD, LPCSTR, LPCSTR, DWORD, int, int, int, int, HWND, HMENU, HINSTANCE, LPVOID);
		WTK_WIN32_R12(HWND, NULL, CreateWindowExW, DWORD, LPCWSTR, LPCWSTR, DWORD, int, int, int, int, HWND, HMENU, HINSTANCE, LPVOID);
		WTK_WIN32_R8(HDWP, NULL, DeferWindowPos, HDWP, HWND, HWND, int, int, int, int, UINT);
		WTK_WIN32_V1(DestroyMenu, HMENU);
		WTK_WIN32_V1(DestroyWindow, HWND);
		WTK_WIN32_V1(DrawMenuBar, HWND);
		WTK_WIN32_R6(int, 0, DrawTextExA, HDC, LPSTR, int, LPRECT, UINT, LPDRAWTEXTPARAMS);
		WTK_WIN32_R6(int, 0, DrawTextExW, HDC, LPWSTR, int, LPRECT, UINT, LPDRAWTEXTPARAMS);
		WTK_WIN32_E2(BOOL, EnableWindow, HWND, BOOL);
		WTK_WIN32_V1(EndDeferWindowPos, HDWP);
		WTK_WIN32_V3(GetClassInfoExA, HINSTANCE, LPCSTR, LPWNDCLASSEXA);
		WTK_WIN32_V3(GetClassInfoExW, HINSTANCE, LPCWSTR, LPWNDCLASSEXW);
		WTK_WIN32_V2(GetClientRect, HWND, LPRECT);
		WTK_WIN32_R1(HANDLE, NULL, GetClipboardData, UINT);
		WTK_WIN32_V1(GetCursorPos, LPPOINT);
		WTK_WIN32_R1(HDC, NULL, GetDC, HWND);
		WTK_WIN32_R1(int, -1, GetMenuItemCount, HMENU);
		WTK_WIN32_V4(GetMenuItemInfoA, HMENU, UINT, BOOL, LPMENUITEMINFOA);
		WTK_WIN32_V4(GetMenuItemInfoW, HMENU, UINT, BOOL, LPMENUITEMINFOW);
		WTK_WIN32_R4(BOOL, -1, GetMessageA, LPMSG, HWND, UINT, UINT);
		WTK_WIN32_R4(BOOL, -1, GetMessageW, LPMSG, HWND, UINT, UINT);
		WTK_WIN32_E1(HWND, GetParent, HWND);
		WTK_WIN32_R1(HGDIOBJ, NULL, GetStockObject, int);
		WTK_WIN32_V4(GetTextExtentPoint32A, HDC, LPCSTR, int, LPSIZE);
		WTK_WIN32_V4(GetTextExtentPoint32W, HDC, LPCWSTR, int, LPSIZE);
		WTK_WIN32_R3(int, 0, GetTextFaceA, HDC, int, LPSTR);
		WTK_WIN32_R3(int, 0, GetTextFaceW, HDC, int, LPWSTR);
		WTK_WIN32_R1(HDC, NULL, GetWindowDC, HWND);
		WTK_WIN32_V2(GetWindowInfo, HWND, PWINDOWINFO);
		WTK_WIN32_E2(LONG, GetWindowLongA, HWND, int);
		WTK_WIN32_E2(LONG, GetWindowLongW, HWND, int);
#ifdef _WIN64
		WTK_WIN32_E2(LONG, GetWindowLongPtrA, HWND, int);
		WTK_WIN32_E2(LONG, GetWindowLongPtrW, HWND, int);
#endif
		WTK_WIN32_V2(GetWindowRect, HWND, LPRECT);
		WTK_WIN32_E3(int, GetWindowTextA, HWND, LPSTR, int);
		WTK_WIN32_E3(int, GetWindowTextW, HWND, LPWSTR, int);
		WTK_WIN32_E1(int, GetWindowTextLengthA, HWND);
		WTK_WIN32_E1(int, GetWindowTextLengthW, HWND);
		WTK_WIN32_R1(LPVOID, NULL, GlobalLock, HGLOBAL);
		WTK_WIN32_E1(BOOL, GlobalUnlock, HGLOBAL);
		WTK_WIN32_V4(InsertMenuItemA, HMENU, UINT, BOOL, LPCMENUITEMINFOA);
		WTK_WIN32_V4(InsertMenuItemW, HMENU, UINT, BOOL, LPCMENUITEMINFOW);
		WTK_WIN32_E1(BOOL, IsClipboardFormatAvailable, UINT);
		WTK_WIN32_R2(HCURSOR, NULL, LoadCursorA, HINSTANCE, LPCSTR);
		WTK_WIN32_R2(HCURSOR, NULL, LoadCursorW, HINSTANCE, LPCWSTR);
		WTK_WIN32_R4(int, 0, MessageBoxA, HWND, LPCSTR, LPCSTR, UINT);
		WTK_WIN32_R4(int, 0, MessageBoxW, HWND, LPCWSTR, LPCWSTR, UINT);
		WTK_WIN32_V1(OpenClipboard, HWND);
		WTK_WIN32_V0(CloseClipboard);
		WTK_WIN32_R1(ATOM, 0, RegisterClassExA, CONST WNDCLASSEXA *);
		WTK_WIN32_R1(ATOM, 0, RegisterClassExW, CONST WNDCLASSEXW *);
		WTK_WIN32_V3(RemoveWindowSubclass, HWND, SUBCLASSPROC, UINT_PTR);
		WTK_WIN32_R1(HWND, NULL, SetActiveWindow, HWND);
		WTK_WIN32_V2(SetMenu, HWND, HMENU);
		WTK_WIN32_V2(SetMenuInfo, HMENU, LPCMENUINFO);
		WTK_WIN32_E3(LONG, SetWindowLongA, HWND, int, LONG);
		WTK_WIN32_E3(LONG, SetWindowLongW, HWND, int, LONG);
#ifdef _WIN64
		WTK_WIN32_E3(LONG, SetWindowLongPtrA, HWND, int, LONG);
		WTK_WIN32_E3(LONG, SetWindowLongPtrW, HWND, int, LONG);
#endif
		WTK_WIN32_V7(SetWindowPos, HWND, HWND, int, int, int, int, UINT);
		WTK_WIN32_V4(SetWindowSubclass, HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR);
		WTK_WIN32_V2(UnregisterClassA, LPCSTR, HINSTANCE);
		WTK_WIN32_V2(UnregisterClassW, LPCWSTR, HINSTANCE);
		WTK_WIN32_V1(UpdateWindow, HWND);
	}
}
